#include "component.h"
#include "device.h"


/* 调试打印接口 */
#define RECORD_LOG(format, ...)    OSAL_LOG(C_GREEN format C_NONE, ##__VA_ARGS__)

#pragma pack(1)
/* 表头 */
typedef struct
{
    uint16_t init_flag;  // 初始化标记
    uint16_t pos;        // 当前环形表的位置（事件记录）
	uint16_t qty;        // 环形表的记录数量（事件记录）
}RecordHead_stu_t;

/* 事件记录环形存储表 */
typedef struct
{
    RecordHead_stu_t  head;                 // 表头信息
	EventRecord_stu_t data[RECORD_MAX_QTY]; // 数据域（600条*9byte）
}Record_stu_t;
#pragma pack()

/* 缓存在RAM里面的记录表（方便数据查找） */
static Record_stu_t recode_list;




/**
  * @brief  保存一条事件记录（存满：覆盖旧记录）
  *
  * @return 保存成功返回SUCCESS 错误返回ERROR
  */
static ErrorStatus Record_Save(EventRecord_stu_t *record)
{
	static uint32_t lastRecordTimeStamp = 0;
    if(lastRecordTimeStamp >= record->timestamp)
    {
        record->timestamp = lastRecordTimeStamp + 1;
    }
    lastRecordTimeStamp = record->timestamp; 
    RECORD_LOG("NvMan_SaveRecord: %02x %02x %02x %02x %02x %ld\r\n",record->eventType,record->eventSource,record->eventCode,
    record->userID,record->appID,record->timestamp);
    /* 保存表头信息 */
    RecordHead_stu_t *pHead = &recode_list.head;
	if (++pHead->pos >= RECORD_MAX_QTY) // 索引位置+1
	{
		pHead->pos = 0;
	}
	if (pHead->qty < RECORD_MAX_QTY)    // 记录数量+1
	{
		pHead->qty++;
	}
    if (OSAL_NvWrite(OSAL_OFFSET(recode_list, head), pHead, sizeof(RecordHead_stu_t)) == ERROR)
    {
        return ERROR;
    }

	/* 保存记录内容 */
    memcpy(&recode_list.data[pHead->pos], record, sizeof(EventRecord_stu_t));
	return OSAL_NvWrite(OSAL_OFFSET(recode_list, data[pHead->pos]), record, sizeof(EventRecord_stu_t));
}

/**
  * @brief  基于时间读取记录差异
  *
  * @param  timestamp：服务器最新记录时间
  * @return 正常返回差异记录的编号，无差异返回FFFF
  */
static uint16_t Record_GetByTime(uint32_t timestamp)
{
	int i, index;

    index = recode_list.head.pos;
    for (i = 0; i < recode_list.head.qty; i++)
	{
		if (recode_list.data[index--].timestamp <= timestamp)
        {
            break;
        }
	 	index = (index < 0) ? (index + RECORD_MAX_QTY) : index;
	}
    return (i == 0) ? 0XFFFF : (i - 1);
}

/**
  * @brief  快速读取N条记录
  *
  * @note   该函数用来一次性上传多条差异记录
  *
  * @param  record：记录数据（每条记录9byte）（时间戳要转成大端模式）
  * @param  start：开始记录编号（一般为0，从最近一条记录开始读）
  * @param  end：结束记录编号
  * @return 读出记录的条数 0失败
  */
static uint16_t Record_QuickGet(uint8_t *record, uint16_t start, uint16_t end)
{
    if (start > end)
    {
        return 0;
    }
	else if (start >= recode_list.head.qty)
	{
		return 0; //记录不存在
	}
	else if (end >= recode_list.head.qty)
	{
		end = recode_list.head.qty - 1; //没那么多条，直接读取实际条数
	}

	for (int i = start; i <= end; i++)
	{
        int index;
        EventRecord_stu_t temp;

        //找到操作位置
        index = recode_list.head.pos - i;
		index = (index < 0) ? (index + RECORD_MAX_QTY) : index;

		//时间戳换成大端模式
        temp = recode_list.data[index];
		temp.timestamp = OSAL_SWAP32(temp.timestamp);

		//赋值
		memcpy(record+((i-start)*9), &temp, 9);
	}
	return end - start + 1;
}

/**
  * @brief  获取记录数量
  * @note   统计前start条记录到前end条记录，这段范围内有效的eventType类型的记录个数
  *
  * @param  start/end：指定的范围
  * @param  eventType：记录类型
  * @return 返回范围内的记录数量
  */
static uint16_t Record_GetQty(uint16_t start, uint16_t end, uint8_t eventType)
{
    if (start > end)
    {
        return 0;
    }
	else if (start >= recode_list.head.qty)
	{
		return 0; //记录不存在
	}
	else if (end >= recode_list.head.qty)
	{
        end = recode_list.head.qty - 1; //没那么多条，直接读取实际条数
    }

    if (eventType == 0XFF)
    {
        return end - start + 1;
    }
    else
    {
        uint16_t count = 0;

        for (int i = start; i <= end; i++)
        {
            int index;

            //找到操作位置
            index = recode_list.head.pos - i;
            index = (index < 0) ? (index + RECORD_MAX_QTY) : index;

            //类型匹配计数+1
            count = (recode_list.data[index].eventType == eventType) ? (count + 1) : (count);
        }
        return count;
    }
}

/**
  * @brief  获取环形表表头位置
  *
  * @return 返回环形表表头位置
  */
static uint16_t Record_GetRecodeListHeadPos(void)
{
    return recode_list.head.pos;
}
/**
  * @brief  获取最近一次事件记录的时间戳
  *
  * @return 记录为空返回：0，正常返回：最近一次事件记录的时间戳
  */
static uint32_t Record_GetLastTimestamp(void)
{
    uint32_t time;

	if (recode_list.head.qty == 0)
	{
		return 0;
	}

    RECORD_LOG("record pos: %d\r\n", recode_list.head.pos);
	time = recode_list.data[recode_list.head.pos].timestamp;
    RECORD_LOG("Record_GetLastTimestamp: %u\r\n", recode_list.data[recode_list.head.pos].timestamp);
    return time;
}



/**
  * @brief  按规则读取一条记录（根据显示光标位置，换算出记录编号，并读取该条记录）
  * @note   显示屏显示记录时用到该函数
  *
  * @param  pRecord：记录数据
  * @param  pNum:记录编号
  * @param  cur_pos：光标位置
  * @return 返回该记录类型
  *         EVENT_TYPE_OPEN_CLOSE：普通开锁记录   
  *         1：双验证开锁记录（密钥1） (kos3.1双重验证开锁不存两条记录 1和2不返回)
  *         2：双验证开锁记录（密钥2） (kos3.1双重验证开锁不存两条记录 1和2不返回)
  *         EVENT_TYPE_PROGRAM：操作记录    
  *         EVENT_TYPE_ALARM：报警记录
  *         0XFF：错误
  */
static uint8_t Record_GetRecordRule(EventRecord_stu_t *pRecord, uint16_t *pNum, uint16_t cur_pos)
{
	int index = 0, count = 0;
	index =recode_list.head.pos;
	for (int num=0; num<recode_list.head.qty; num++)
	{
		if (cur_pos == num + count)
		{
			*pNum = num;
			*pRecord = recode_list.data[index];
			switch(recode_list.data[index].eventType)
			{
				case EVENT_TYPE_OPEN_CLOSE: return  EVENT_TYPE_OPEN_CLOSE;
				case EVENT_TYPE_PROGRAM: return EVENT_TYPE_PROGRAM;
				case EVENT_TYPE_ALARM: return EVENT_TYPE_ALARM;
				default: return 0XFF;
			}
		}

		// if (recordBuff[index].type == RECORD_TYPE_OPEN_DOOR && recordBuff[index].data.openDoor.keys2Type != 0XFF)
		// {
		// 	count++;//统计双重验证开锁记录的数量
		// }

		// if (cur_pos == num + count)
		// {
		// 	*pNum = num;
		// 	*pRecord = recordBuff[index];
		// 	return 2;
		// }

		index--;
		index = (index < 0) ? (index + RECORD_MAX_QTY) : index;
	}
	return 0XFF;//错误
}

/**
  * @brief  读一条指定类型的记录数据
  *
  * @return SUCCESS  ERROR
  */
static ErrorStatus Record_Read(EventRecord_stu_t *record, uint16_t number, uint8_t eventType)
{
    uint16_t count = 0;

    if (recode_list.head.qty == 0 || number >= recode_list.head.qty)
    {
        return ERROR;
    }

    for (int i=0; i < recode_list.head.qty; i++)
    {
        int index;

        index = recode_list.head.pos - i;
        index = (index < 0) ? (index + RECORD_MAX_QTY) : index;

        if(eventType == EVENT_TYPE_ALL)
        {
            if (count++ == number)
            {
                memcpy(record, &recode_list.data[index], sizeof(EventRecord_stu_t));
                return SUCCESS;
            }
        }
        else
        {
            if (recode_list.data[index].eventType == eventType)
            {
                if (count++ == number)
                {
                    memcpy(record, &recode_list.data[index], sizeof(EventRecord_stu_t));
                    return SUCCESS;
                }
            }
        }
    }
    return ERROR;
}

/**
  * @brief  删除全部记录（恢复出厂设置时用到）
  *
  * @return SUCCESS  ERROR
  */
static ErrorStatus Record_Delete(void)
{
    recode_list.head.init_flag = 0xFAFA;
    recode_list.head.qty = 0;
    recode_list.head.pos = 0;
    return OSAL_NvWrite(OSAL_OFFSET(recode_list, head), &recode_list.head, sizeof(RecordHead_stu_t));
}

/**
  * @brief  事件记录初始化
  *
  * @note   1、记录表恢复到RAM    2、注册API接口
  */
static void Record_Init(void)
{
    static FlagStatus power_on = SET;

    if (power_on == SET)
    {
        power_on = RESET;

        OSAL_NvRead(0, &recode_list, sizeof(recode_list));
        if (recode_list.head.init_flag != 0XFAFA)
        {
            Record_Delete();
        }

        SYS_API(Record_Save);
        SYS_API(Record_GetByTime);
        SYS_API(Record_QuickGet);
        SYS_API(Record_GetQty);
        SYS_API(Record_GetLastTimestamp);
        SYS_API(Record_Read);
        SYS_API(Record_Delete);
        SYS_API(Record_GetRecodeListHeadPos);
        SYS_API(Record_GetRecordRule);
    }
}

/**
  * @brief  事件记录任务函数
  *
  * @note
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Record_Task(uint32_t event)
{
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		RECORD_LOG("Record task start\r\n");
		Record_Init();
		return ( event ^ EVENT_SYS_START );
	}
	
	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
		return ( event ^ EVENT_SYS_SLEEP );
	}

    return 0;
}
COMPONENT_TASK_EXPORT(COMP_RECORD, Record_Task, 6 * 1024);
